~res = "/home/justin/noisesmith-linux-audio/joy/res/";
~imDict = this.executeFile( ~res ++ "info.sc" );
~paras = this.executeFile( ~res ++ "maclowText.sc" );
~resetOsc = {
	SwingOSC.default.quit;
	SwingOSC.program = "/usr/local/bin/SwingOSC.jar";
	SwingOSC.default.options.javaOptions =
	"-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel";
};

~resetOsc.();

~gameStart = {
	// little bug here between swingosc and my WM
	"xwit -move 0 0 -names 'J O Y'".unixCmd;
	~leftHand = Sprite.new( [ JSCImage.open( ~res ++ "leftHand.png" ) ],
		type: \movable,
		// scale: 0.25, //50/( ~imDict.at( \lefthand )[ 0 ] ),
		width: ~imDict[ \leftHand ][ 0 ],
		height: ~imDict[ \leftHand ][ 1 ],
		symbol: \left,
		enter: { | s |
			switch( s.symbol,
				\E, { ~switcheroo.( "E", 2, 0 ) },
				\Z, { ~switcheroo.( "Z", 3, 1 ) },
				\R, { ~switcheroo.( "R", 2, 2 ) },
				\A, { ~switcheroo.( "A", 3, 3 ) },
				\P, { ~switcheroo.( "P", 2, 4 ) },
				\O, { ~switcheroo.( "O", 3, 5 ) },
				\U, { ~switcheroo.( "U", 2, 6 ) },
				\N, { ~switcheroo.( "N", 3, 7 ) },
				\D, { ~switcheroo.( "D", 2, 8 ) } )
		},
		leave: { | s |
			if( s.symbol.asString.size == 1, {
				if( ~game.obstacles.includes( s ), {
					~game.remSprite( s );
					~letterCount = ~letterCount - 1;
					~countDisplay.string = ~letterCount;
					if( ~letterCount <= 0, { ~newPara.() } )
				} ) } ) } );
	~game.addSprite( ~leftHand, 600 );
	~rightHand = Sprite.new( [ JSCImage.open( ~res ++ "rightHand.png" ) ],
		type: \movable,
		// scale: 0.25, // scale: 50/( ~imDict.at( \righthand )[ 0 ] ),
		width: ~imDict[ \rightHand ][ 0 ],
		height: ~imDict[ \rightHand ][ 1 ],
		symbol: \right,
		enter: { | s |
			switch( s.symbol,
				\E, { ~switcheroo.( "E", 1, 9 ) },
				\Z, { ~switcheroo.( "Z", 0, 8 ) },
				\R, { ~switcheroo.( "R", 1, 7 ) },
				\A, { ~switcheroo.( "A", 0, 6 ) },
				\P, { ~switcheroo.( "P", 1, 5 ) },
				\O, { ~switcheroo.( "O", 0, 4 ) },
				\U, { ~switcheroo.( "U", 1, 3 ) },
				\N, { ~switcheroo.( "N", 0, 2 ) },
				\D, { ~switcheroo.( "D", 1, 1 ) } )
		},
		leave: { | s |
			if( s.symbol.asString.size == 1, {
				if( ~game.obstacles.includes( s ), {
					~game.remSprite( s );
					~letterCount = ~letterCount - 1;
					~countDisplay.string = ~letterCount;
					if( ~letterCount <= 0, { ~newPara.() } )
				} ) } ) } );
	~game.addSprite( ~rightHand, 600 );
	~letter =  StaticText( ~game.window, Rect( 40, 40, 1024, 768 ) );
	~letter.font = JFont( "foo", 700 );
	~inds = [
		StaticText( ~game.window, Rect( 820, 10, 100, 15 ) ),
		StaticText( ~game.window, Rect( 820, 30, 100, 15 ) ),
		StaticText( ~game.window, Rect( 930, 10, 100, 15 ) ),
		StaticText( ~game.window, Rect( 930, 30, 100, 15 ) )
	];
	~countDisplay = StaticText( ~game.window, Rect( 740, 10, 150, 50 ) );
	~countDisplay.font = Font( "foo", 50 );
	~bg = Sprite.new( [ JSCImage.open( ~res ++ "bg0.png" ) ] );
	~bgCount = 0;
	~txt = StaticText( ~game.window, Rect( 0, 0, 1024, 768 ) );
	~txt.font = JFont( "foo", 100 );
	~txt.stringColor = Color.new( 0.1, 0.5, 0.1 );
	~failTxt = StaticText( ~game.window, Rect( 0, 0, 1024, 768 ) );
	~failTxt.font = JFont( "foo", 100 );
	~failTxt.stringColor = Color.new( 1, 0, 0 );
	~newPara.();
	~syn = Synth( \blurg );
	[ [ \sinAmp,    1 ],
		[ \sinPan,    11 ],
		[ \loopAmp0,  2 ],
		[ \loopPan0,  12 ],
		[ \loopAmp1,  3 ],
		[ \loopPan1,  13 ],
		[ \masterAmp, 9 ], 
		[ \masterPan, 19 ] ].do{ | x |
			CCResponder( {
				| src, ch, num, val |
				~syn.set( x[ 0 ], val / 127 )
			}, nil,nil, x[ 1 ] ) };
	~params.do{ | k, i |
		~syn.map( k, ~rawSticks[ i ] ) };
	4.do{ | i |
		~switcheroo.( " ", i, i ) };
};
	
~params = [ \freq, \mod, \mod2, \mod3,
	\loopIn0, \loopLen0, \decayTime0,
	\loopIn1, \loopLen1, \decayTime1 ];

~newPara = {
	~game.obstacles.do{ | ob | ~game.remSprite( ob ) };
	~iX = 112;
	~iY = 84;
	~letterCount = 0;
	~maxLetters = 20;
	~paras[ ~bgCount ].do { | l |
		if( l.isUpper, { ~letterCount = ~letterCount + 1 } ) };
	~excessLetters = ( ~letterCount / ~maxLetters ).floor;
	~letterCount = 0;
	~paras[ ~bgCount ].do{ | letter |
		var sprite;
		var referent = ~imDict[ letter.asSymbol ];
		// [ \letterCount, ~letterCount, \excess, ~excessLetters ].postln;
		if ( referent.notNil, {
				if(  letter.isUpper, {
					if( ~letterCount % ~excessLetters == 0, {
						if( referent[ 3 ].isNil, {
							referent[ 3 ] =
							JSCImage.open( ~res++letter++".png" )
						} );
						sprite = Sprite.new( [ referent[ 3 ] ],
							type: \obstacle,
							symbol: letter.asSymbol );
						~game.addSprite( sprite, 1000 );
						sprite.x = ~iX;
						sprite.y = ~iY+referent[ 2 ];
					} );
					~letterCount = ~letterCount + 1;
				} );
			~iX = referent[ 0 ] + ~iX + 24;
		}, {
			if( letter == $\n, {
				~iY = 30 + ~iY;
				~iX = 112
			}, {
				~iX = 10 + ~iX } ) } ) };
	if( ~letterCount > 20, { ~letterCount = 19 } );
	~countDisplay.string = ~letterCount;
	~bg.images[ 0 ].destroy;
	~bg.images[ 0 ] = JSCImage.open( ~res ++ "bg" ++ ~bgCount  ++ ".png" );
	~bg.x = 112;
	~bg.y = 84;
	~game.addSprite( ~bg, 500 );
	r = Routine{
		var count = ~bgCount;
		7.do{
			~txt.string = " STANZA " ++ count ++ " START!!!";
			0.4.rand.wait;
			~txt.string = "";
			0.1.rand.wait;
		}
	};
	r.play;
	~bgCount = ( ~bgCount + 1 ) % 37;
};

~switcheroo = { | letter, stick, param |
	~sticks[ stick ] = ~rawSticks[ param ];
	~inds[ stick ].string = ~params[ param ].asString;
	Routine{
		var count = ~bgCount;
		var color = Color.new( 1.0.rand, 1.0.rand, 1.0.rand,
			0.5.rand + 0.5 );
		var bounds = Rect( 700.rand - 100, 300.rand - 200, 1024, 768 );
		14.do{
			~letter.bounds = bounds;
			~letter.stringColor = color;
			~letter.string = letter;
			0.2.rand.wait;
			~letter.string = "";
			0.2.rand.wait } }.play };

Routine { fork {
	SwingOSC.default.boot;
	~joyous = LogJoy.new;
	if( ~joyous.joyStick.notNil, {
		~joys = [ ~joyous.x0, ~joyous.y0, ~joyous.x1, ~joyous.y1 ]
	} );
	2.wait;
	s.boot;
	5.wait;
	// ~blank = JSCImage.open( ~res ++ "blank.png" );
	~rawSticks = 10.collect{ Bus.control };
	~sticks = ~rawSticks[ 0 .. 3 ];
	~game = Game.new( "J O Y", 1024, 768 );
	~sliders = [
		{ | v | ~leftHand.x  = v * ( ~game.width  - ~leftHand.width ) },
		{ | v | ~leftHand.y  = v * ( ~game.height - ~leftHand.height ) },
		{ | v | ~rightHand.x = v * ( ~game.width  - ~rightHand.width ) },
		{ | v | ~rightHand.y = v * ( ~game.height - ~rightHand.height ) }
	];
	if( ~joyous.joyStick.notNil, {
		~rel = [ \x0, \y0, \x1, \y1 ].collect{ | symbol, index |
			RelativeMotion(
				{ | v, d, c |
					~sticks[ index ].set( v );
					~sliders[ index ].value( v ) },
				~joys[ index ],
				symbol
			) };
		~rel.do{ | rel |
			~game.addAction( rel.symbol,
				{ | counter | rel.update( counter ) } );
		};
	} );
	SynthDef( \blurg, {
		| freq = 0.5, mod = 0.5, mod2 = 0.5, mod3 = 0.5,
		loopIn0 = 0.5, loopLen0 = 0.5, decayTime0 = 0.5,
		loopIn1 = 0.5, loopLen1 = 0.5, decayTime1 = 0.5,
		sinAmp = 0.85, sinPan = 0.5,
		loopAmp0 = 1, loopPan0 = 0,
		loopAmp1 = 1, loopPan1 = 1,
		masterAmp = 0, masterPan = 0.5, master = 0.5 |
		var sinL = \amp.asSpec.map(
			10 * masterAmp * ( 1 - masterPan ) * sinAmp * ( 1 - sinPan ) );
		var sinR = \amp.asSpec.map(
			10 * masterAmp * masterPan * sinAmp * sinPan );
		var loop0L = \amp.asSpec.map(
			20* masterAmp * ( 1 - masterPan ) * loopAmp0 * ( 1 - loopPan0 ) );
		var loop0R = \amp.asSpec.map(
			20 * masterAmp * masterPan * loopAmp0 * loopPan0 );
		var loop1L = \amp.asSpec.map(
			20* masterAmp * ( 1 - masterPan ) * loopAmp1 * ( 1 - loopPan1 ) );
		var loop1R = \amp.asSpec.map(
			20 * masterAmp * masterPan * loopAmp1 * loopPan1 );
		var sin = SinOsc.ar(
			\freq.asSpec.map( freq )
			* SinOsc.ar( \freq.asSpec.map(
				mod * SinOsc.ar( \freq.asSpec.map( mod3 ) ) ), 0,
				\freq.asSpec.map( mod2 ) ) );
		var loop0 = HPF.ar( CombN.ar(
			( sin + LocalIn.ar() ).tanh * \amp.asSpec.map( loopIn0 ),
			3,
			[ 0, 10 ].asSpec.map( loopLen0 ),
			[ 0, 100 ].asSpec.map( decayTime0 * loopLen0 ) ),
			20 );
		var loop1 = HPF.ar( CombN.ar(
			( sin + loop0 ).tanh * \amp.asSpec.map( loopIn1 ).tanh,
			17,
			[ 0, 10 ].asSpec.map( loopLen1 ),
			[ 0, 1000 ].asSpec.map( decayTime1 * loopLen1 ) ),
			20 );
		LocalOut.ar( loop1 );
		Out.ar( 0,
			[ ( ( loop0 * loop0L ) + ( loop1 * loop1L ) +
				( sin * sinL ) ).tanh,
				( ( loop0 * loop0R ) + ( loop1 * loop1R ) +
					( sin * sinR ) ).tanh
			] ) } ).send(s);
	~game.start;
	if( ~joyous.joyStick.notNil, {
		~joyous.fronts[ 0 ].addAction( \overRide, { | v |
			if( v == 1, {
				~marquee.stop;
				~marqueeTop.destroy;
				~marqueeBottom.destroy;
				~gameStart.();
				// start game, replace action of button
				~joyous.fronts[ 0 ].addAction( \overRide, { | v |
					if( v == 1, {
						r = Routine{
							22.do{
								~failTxt.string = "     ☣☣ YOU FAIL ☣☣";
								0.5.rand.wait;
								~failTxt.string = "";
								0.1.rand.wait;
							};
							~newPara.()
						};
						r.play;
					} ) } ) } ) } ) } );
	1.wait;
	// little bug here between swingosc and my WM
	"xwit -move 0 0 -names 'J O Y'".unixCmd;
	~marqueeTop =  StaticText( ~game.window, Rect( 40, 40, 1024, 80 ) );
	~marqueeTop.font = JFont( "foo", 80 );
	~marqueeTop.stringColor = Color.new( 1, 0, 0 );
	~marqueeBot =  StaticText( ~game.window, Rect( 40, 400, 1024, 80 ) );
	~marqueeBot.font = JFont( "foo", 80 );
	~topStrings = [ "Erasure Racer", "Erasure Racer",
		"push \"fail\" button to start" ];
	~botStrings = [ "by justin smith\nnoisesmith@gmail.com\nhttp://code.google.com/p/noisesmith-linux-audio", "music inspired by Yasunao Tone", "text from \"Words and Ends from Ez\", by Jackson Mac Low", "realized with SuperCollider and Linux" ];
	~marquee = Routine{
		loop { | count |
			5.0.rand.wait;
			~marqueeTop.string = ~topStrings@@count;
			~marqueeBot.string = ~botStrings@|@count } }.play } }.play;

/*
	~rawSticks.do{ | x | x.get{ | v | [ x, v ].postln } }
	~game.obstacles.size
*/

/*
	~sticks = [ ~rawSticks[ 4 ], ~rawSticks[ 5 ], ~rawSticks[ 6 ] ]
	~sticks = [ ~rawSticks[ 0 ], ~rawSticks[ 1 ], ~rawSticks[ 2 ], ~rawSticks[ 3 ] ]
	s.scope();
*/
/*
~paras[ 4 ]
*/